//
//  CustomFunction.m
//  GKeyboard
//
//  Created by seven on 2018/12/12.
//  Copyright © 2018 innotech. All rights reserved.
//

#import "CustomFunction.h"
#include <objc/runtime.h>
#import <mach/mach_time.h>
#import <pthread.h>
//计算block执行时间
CGFloat custom_time_block_log(NSString *logMsg, void (^block)(void)) {
    
#if DEBUG
    mach_timebase_info_data_t info;
    BOOL shouldCost = logMsg.length > 0 && mach_timebase_info(&info) == KERN_SUCCESS ;
    uint64_t start = 0;
    if (shouldCost) {
        start = mach_absolute_time ();
    }
#endif
    
    block ();
    
#if DEBUG
    if (shouldCost) {
        uint64_t end = mach_absolute_time ();
        uint64_t elapsed = end - start;
        uint64_t nanos = elapsed * info.numer / info.denom;
        CGFloat cost = (CGFloat)nanos / NSEC_PER_SEC;
        printf("%s cost time : %f\n",logMsg.UTF8String , cost);
        return cost;
    }
#endif
    
    return 0.0;
}

CGFloat custom_time_block (void (^block)(void)) {
    return custom_time_block_log(nil, block);
}

//异步主线程延迟执行.
void custom_dispatch_after_log(NSString* logMsg, float delayTime, void(^delayBlock)(void)){
    if (delayTime == 0) {
        if (pthread_main_np()) {
            custom_time_block_log(logMsg, delayBlock);
        } else {
            dispatch_async(dispatch_get_main_queue(), ^{
                custom_time_block_log(logMsg, delayBlock);
            });
        }
        return;
    }
    dispatch_time_t time=dispatch_time(DISPATCH_TIME_NOW, delayTime*NSEC_PER_SEC);
    dispatch_after(time, dispatch_get_main_queue(), ^{
        custom_time_block_log(logMsg, delayBlock);
    });
};

void custom_dispatch_after(float delayTime, void(^delayBlock)(void)){
    custom_dispatch_after_log(nil, delayTime, delayBlock);
}


void custom_dispatch_global_after_log(NSString* logMsg, float delayTime, void(^delayBlock)(void)){
    @autoreleasepool {
        dispatch_queue_t queue = YYDispatchQueueGetForQOS(NSQualityOfServiceUtility);
        if (delayTime == 0) {
            if (pthread_main_np()) {
                dispatch_async(queue, ^{
                    custom_time_block_log(logMsg, delayBlock);
                });
            } else {
                custom_time_block_log(logMsg, delayBlock);
            }
            return;
        }
        dispatch_time_t time=dispatch_time(DISPATCH_TIME_NOW, delayTime*NSEC_PER_SEC);
        dispatch_after(time, queue, ^{
            custom_time_block_log(logMsg, delayBlock);
        });
    }
};

void custom_dispatch_global_after(float delayTime, void(^delayBlock)(void)){
    custom_dispatch_global_after_log(nil, delayTime, delayBlock);
}

//hook 系统方法
void swizzleMethod(id class, SEL originalSelector, SEL swizzledSelector){
    
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    
    // class_addMethod will fail if original method already exists
    BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    
    // the method doesn’t exist and we just added one
    if (didAddMethod) {
        class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    }
    else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    
}

#pragma mark - cancel delay

DisQueueTask MainDelay(NSTimeInterval time,void (^task)(void)) {
    dispatch_queue_t queue = dispatch_get_main_queue();
    //dispatch_queue_t queue = YYDispatchQueueGetForQOS(NSQualityOfServiceUserInteractive);
    if (time == 0) {
        if (pthread_main_np()){
            task();
        }else {
            dispatch_async(queue, task);
        }
        return nil;
    }
    __block void (^closure)(void) = task;
    __block DisQueueTask result;
    DisQueueTask delayedClosure = ^(BOOL cancel){
        if (closure) {
            if (!cancel) {
                void (^internalClosure)(void) = closure;
                dispatch_async(queue, internalClosure);
            }
        }
        closure = nil;
        result = nil;
    };
    
    result = delayedClosure;
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), queue, ^{
        if (delayedClosure) {
            delayedClosure(NO);
        }
    });
    return result;
}

DisQueueTask GlobalDelay(NSTimeInterval time,void (^task)(void)) {
    dispatch_queue_t queue = YYDispatchQueueGetForQOS(NSQualityOfServiceUtility);
    if (time == 0) {
        if (!pthread_main_np()){
            task();
        }else {
            dispatch_async(queue, task);
        }
        return nil;
    }
    __block void (^closure)(void) = task;
    __block DisQueueTask result;
    DisQueueTask delayedClosure = ^(BOOL cancel){
        if (closure) {
            if (!cancel) {
                void (^internalClosure)(void) = closure;
                dispatch_async(queue, internalClosure);
            }
        }
        closure = nil;
        result = nil;
    };
    
    result = delayedClosure;
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), queue, ^{
        if (delayedClosure) {
            delayedClosure(NO);
        }
    });
    return result;
}



@implementation CustomFunction

@end
